/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.client.veditor.model;

import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.SimpleAttributeSet;
import offset.nodes.client.editor.model.messages.TemplateInformation;

class VirtualElementInstance extends VirtualElement {

    VirtualElement v = null;
    VirtualElementInstance parent = null;
    int multipleIndex = MI_NONE;
    boolean last = false;
    public static final int MI_NONE = -1;
    public static final int MI_LAST = -2;
    VirtualBlock virtualBlock;

    public VirtualElementInstance(VirtualElement v, VirtualBlock virtualBlock) {
        super(v.getName(), v.isDataElement(), virtualBlock);
        this.virtualBlock = virtualBlock;
        this.v = v;
        if (isMultiple())
            setMultipleIndex(0);
    }

    public String toString() {
        return v.toString();
    }

    /**
     * Check, if the real v has the requested multipleIndex
     *
     * @param v the virtual v with the requested multipleIndex
     * @param e the real v
     * @return the result of the check
     */
    protected boolean isEquivalent(Element e) {
        if (e instanceof VirtualElement)
            if (virtualBlock.getModel().getChildIndex(getVirtualElement()) != virtualBlock.getModel().getChildIndex(e))
                return false;
        
        if (!isMultiple() || e instanceof VirtualElement)
            return true;

        if (getMultipleIndex() == VirtualElementInstance.MI_LAST)
            return virtualBlock.isLastMultipleIndex(getVirtualElement(), e);
        else
            return virtualBlock.getMultipleIndex(getVirtualElement(), e) == getMultipleIndex();
    }

    public VirtualElement getVirtualElement() {
        return v;
    }

    public void setParentElement(VirtualElement parent) {
        v.setParentElement(parent);
    }

    public void setMultiple(boolean multiple) {
        v.setMultiple(multiple);
    }

    public void setIsLeaf(boolean isLeaf) {
        v.setIsLeaf(isLeaf);
    }

    public void setDataElement(boolean dataElement) {
        v.setDataElement(dataElement);
    }

    public void setContent(String content) {
        v.setContent(content);
    }

    public boolean isMultiple() {
        return v.isMultiple();
    }

    public boolean isLeaf() {
        return v.isLeaf();
    }

    public boolean isDataElement() {
        return v.isDataElement();
    }

    public VirtualElement getVirtualElement(int index) {
        return v.getVirtualElement(index);
    }

    public VirtualBlock getVirtualBlock() {
        return v.getVirtualBlock();
    }

    public int getStartOffset() {
        return v.getStartOffset();
    }

    public Element getParentElement() {
        return v.getParentElement();
    }

    public VirtualElementInstance getParentInstance() {
        return parent;
    }

    public void setParentInstance(VirtualElementInstance parent) {
        this.parent = parent;
    }

    public VirtualElement getParent() {
        if (parent == null)
            return v.getParent();
        return parent;
    }

    public String getName() {
        return v.getName();
    }

    public int getEndOffset() {
        return v.getEndOffset();
    }

    public int getElementIndex(int offset) {
        return v.getElementIndex(offset);
    }

    public int getElementCount() {
        return v.getElementCount();
    }

    public Element getElement(int index) {
        return v.getElement(index);
    }

    public Document getDocument() {
        return v.getDocument();
    }

    public String getContent() {
        return v.getContent();
    }

    public SimpleAttributeSet getAttributes() {
        return v.getAttributes();
    }

    public void setAttributes(SimpleAttributeSet attributes) {
        v.setAttributes(attributes);
    }
    
    public boolean equals(Element e) {
        return v.equals(e) && isEquivalent(e);
    }

    protected Object clone() throws CloneNotSupportedException {
        return v.clone();
    }

    public void addChild(VirtualElement child) {
        v.addChild(child);
    }

    public int getMultipleIndex() {
        return multipleIndex;
    }

    public void setMultipleIndex(int multipleIndex) {
        this.multipleIndex = multipleIndex;
    }

    public boolean isLast() {
        return last;
    }

    public void setLast(boolean last) {
        this.last = last;
    }

    public VirtualElementInstance previousInstance() {
        return previousInstance(false);
    }

    public VirtualElementInstance previousInstance(boolean skipMultiple) {
        VirtualElementInstance previous = null;
        if (isMultiple() && !skipMultiple && virtualBlock.getModel().canEdit(this)) {
            previous = new VirtualElementInstance(v, virtualBlock);
            if (multipleIndex > 0)
                previous.setMultipleIndex(multipleIndex - 1);
            else
                previous.setMultipleIndex(0);
        } else {
            int index = virtualBlock.getModel().getChildIndex(v);
            if (index == 0)
                return null;
            previous = new VirtualElementInstance(v.getParent().getVirtualElement(index - 1), virtualBlock);
        }
        previous.setParentInstance(parent);
        return previous;
    }

    public VirtualElementInstance nextInstance() {
        return nextInstance(false);
    }

    public VirtualElementInstance nextInstance(boolean skipMultiple) {
        VirtualElementInstance next = null;
        if (isMultiple() && !skipMultiple) {
            next = new VirtualElementInstance(v, virtualBlock);
            next.setMultipleIndex(multipleIndex + 1);
        } else {
            int index = virtualBlock.getModel().getChildIndex(v);
            if (index == getParent().getElementCount() - 1)
                return null;
            next = new VirtualElementInstance(v.getParent().getVirtualElement(index + 1), virtualBlock);
        }
        next.setParentInstance(parent);
        return next;
    }

    public VirtualElementInstance childInstance(int index) {
        if (index < 0 || index >= v.getElementCount())
            return null;
        VirtualElementInstance child = new VirtualElementInstance(getVirtualElement(index), virtualBlock);
        child.setParentInstance(this);
        return child;
    }

    @Override
    public TemplateInformation getTypeInformation() {
        return v.getTypeInformation();
    }
}
